package cool.mtc.security.auth.password;

import cool.mtc.core.result.ResultConstant;
import cool.mtc.core.util.StringUtil;
import cool.mtc.security.auth.AuthFormSupport;
import cool.mtc.security.auth.AuthTemplate;
import cool.mtc.security.auth.AuthToken;
import cool.mtc.security.data.model.UserDetailsSupport;
import cool.mtc.security.exception.AuthException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * @author yz
 */
public abstract class PasswordAuthTemplate extends AuthTemplate {
    protected static final PasswordEncoder PASSWORD_ENCODER = new BCryptPasswordEncoder();

    @Override
    protected void handlePreCheck(AuthFormSupport formSupport) {
        PasswordAuthForm form = (PasswordAuthForm) formSupport;

        if (StringUtil.isEmpty(form.getUsername())) {
            throw new AuthException(ResultConstant.A0410, "用户名不允许为空");
        }
        if (StringUtil.isEmpty(form.getPassword())) {
            throw new AuthException(ResultConstant.A0410, "密码不允许为空");
        }

        // 验证码检查
        if (this.isVerifyCodeError(form.getVerifyCode())) {
            throw new AuthException(ResultConstant.A0240, "验证码错误");
        }
    }

    @Override
    protected void handlePostCheck(AuthFormSupport formSupport, UserDetailsSupport userSupport) {
        PasswordAuthForm form = (PasswordAuthForm) formSupport;

        if (!PASSWORD_ENCODER.matches(form.getPassword(), userSupport.getPassword())) {
            throw new AuthException(ResultConstant.A0210, "用户名或密码错误");
        }
    }

    @Override
    protected AuthToken handleResult(AuthFormSupport formSupport, UserDetailsSupport userSupport) {
        String token = this.generateToken(userSupport);
        return new PasswordAuthToken((PasswordAuthForm) formSupport, token, userSupport.getAuthorities());
    }

    protected abstract String generateToken(UserDetailsSupport userSupport);

    /**
     * 验证码是否错误
     */
    protected abstract boolean isVerifyCodeError(Object verifyCode);
}
